<?

/*****************************************************************************

Heartdropper Twitter Grabber 0.0.3
Copyright (C) 2013 by Jacob Rose, Steve Emmerich, Zaal Tonia

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*****************************************************************************/

require('tmhOAuth/tmhOAuth.php');

class heartdropper_twitter_grabber
{
	function __construct()
	{
		include "/usr/home/soyamonger/public_html/heartdropper.com/MySQLPasswords.php";
		$this->db = new PDO(
			'mysql:host=' . $MYSQL_HOSTNAME . ';' .
			'dbname=' . $MYSQL_DATABASE . ';' .
			'port=' . $MYSQL_PORT,
		        $MYSQL_USERNAME,
		        $MYSQL_PASSWORD
		);

		include "/usr/home/soyamonger/public_html/heartdropper.com/TwitterTokens.php";
		$this->twitter = new tmhOAuth(
			array(
				'consumer_key' => $twitter_access['consumer_key'],
				'consumer_secret' => $twitter_access['consumer_secret'],
				'user_token' => $twitter_access['token'],
				'user_secret' => $twitter_access['token_secret']
			)
		);

		/* Gives the text we send back to users */
		$this->powerups = array(
			'heart' => "Dropping a heart on building #%s.",
			'ammo' => "Dropping a bullet on building #%s.",
			'speed' => "Dropping a speed booster at building #%s.",
			'ufo' => "Look! Up in the sky! Is that a UFO? No, wait, just a cloud.",
			'dance' => "Let's see *your* Gangnam style.",
			'sinistar' => "Beware -- I live!"
		);

		$this->quips = array(
			'Huzzah!',
			'Bazinga!',
			'FTW!',
			'YOLO!',
			'Oy!',
			'Interstellar!',
			'Earthtastic!',
			"Intergalactic? Planetary.",
			'Klaatu! Barada nikto!',
			'Live Long and Prosper!',
			'Probe consent? (y/n)',
			'Aliens took arr jerbs!',
			'Respect my authoritay!',
			'Thanks for the cattle!',
			'The spice must flow!',
			"IT'S A COOK BOOK!",
			"EX-TER-MIN-ATE!",
			"Make it so!",
			"Fire phasers!",
			"Warp factor 9!",
			"Beam me up!",
			"Reboot!",
			"Go Team Zen4SugarLemur!",
			"Zaals of fury!",            // Team member Zaal Tonia!
			"Bo calling mothership!",    // Team member Bo Banducci!
			"Reybomb.com",               // Team member Rey Leon Lor!
			"Go Blaquejag!",             // Team member William Anderson!
			"Go SCUBA Steve!",           // Team member Steve Emmerich!
			"Codemonkey Jacob, yo.",     // Team member Jacob Rose!
			"Otaku Devin on the scene.", // Team member Devin Rainey!
			"Go Diego, go!",             // Team member Diego Ruiz!
			"Some parts made in Craig."  // Team member Craig Landen!
		);
	}

	/* query_twitter() makes the Twitter API pull and stores the data */
	function query_twitter()
	{
		$get_last_twitter_id = $this->_do_sql('SELECT max(tweet_id) as last_tweet_id FROM twitter');
		$last_twitter_id = 0;
		if ( is_array( $get_last_twitter_id ) )
		{
			$last_twitter_id = $get_last_twitter_id[0]['last_tweet_id'];
		}

		$tweet_set = array();
		$query_twitter_url = 'http://search.twitter.com/search.json?q=' .
			urlencode('to:heartdropper') . 
			'&since_id=' . urlencode( $last_twitter_id ) .
			'&include_entities=true&with_twitter_user_id=true&result_type=mixed';
		$curl_query_twitter = curl_init( $query_twitter_url );
		curl_setopt( $curl_query_twitter, CURLOPT_VERBOSE, 0 );
		curl_setopt( $curl_query_twitter, CURLOPT_NOBODY, 0 );
		curl_setopt( $curl_query_twitter, CURLOPT_HEADER, 0 );
		curl_setopt( $curl_query_twitter, CURLOPT_FOLLOWLOCATION, 1 );
		curl_setopt( $curl_query_twitter, CURLOPT_RETURNTRANSFER, 1 );
		$body = curl_exec( $curl_query_twitter );
		$result = curl_getinfo( $curl_query_twitter );
		if ( intval( $result['http_code'] ) == 200 )
		{
			$decode = json_decode( $body, true );
			$tweets = Array();
			if ( is_array( $decode ) && is_array( $decode['results'] ) )
			{
				$tweets = $decode['results'];
			}

			foreach ( $tweets as $key => $tweet )
			{
				$parsed = $this->parse_tweet( $tweet['text'] );

				/* Try to get an avatar for this user -- we do this before 
				   inserting the tweet in case the client polls us for tweets
				   right after we insert; this way, if they need the avatar
				   for a new user, it'll already be there. */
				$check_avatar = $this->_do_sql(
					'SELECT 1 FROM twitter_user_avatars WHERE profile_image_url=?',
					Array(
						$tweet['profile_image_url'] 
					)
				);
				if ( ! is_array( $check_avatar ) || ! array_key_exists( 0, $check_avatar ) )
				{
					$curl_get_image = curl_init( $tweet['profile_image_url'] );
					curl_setopt( $curl_get_image, CURLOPT_VERBOSE, 0);
					curl_setopt( $curl_get_image, CURLOPT_NOBODY, 0);
					curl_setopt( $curl_get_image, CURLOPT_HEADER, 0);
					curl_setopt( $curl_get_image, CURLOPT_FOLLOWLOCATION, 1);
					curl_setopt( $curl_get_image, CURLOPT_RETURNTRANSFER, 1);
					$image_body = curl_exec( $curl_get_image );
					$image_result = curl_getinfo( $curl_get_image );
					if ( intval( $image_result['http_code'] ) == 200 )
					{
						$this->_do_sql(
							'INSERT INTO twitter_user_avatars ' .
							'( profile_image_url, profile_image, image_content_type, created ) ' .
							'VALUES ( ?, ?, ?, unix_timestamp( now() ) )',
							Array(
								$tweet['profile_image_url'],
								$image_body,
								$image_result['content_type']
							)
						);
					}
				}

				/* See if we know this Twitter user already; if not, store user data
				   and plan to send them a welcome tweet */
				$get_user_exists = $this->_do_sql(
					'SELECT 1 FROM twitter_users WHERE twitter_user_id=?',
					array( $tweet['from_user_id_str'] )
				);
				$new_user = 0;
				if ( ! is_array( $get_user_exists ) || ! array_key_exists( 0, $get_user_exists ) )
				{
					/* Add to our user database */
					$this->_do_sql(
						'INSERT INTO twitter_users ' .
						'( twitter_user_id, twitter_user_name, profile_image_url ) ' .
						'VALUES ( ?, ?, ? )',
						array(
							$tweet['from_user_id_str'],
							$tweet['from_user'],
							$tweet['profile_image_url']
						)
					);

					/* Send welcome tweet -- using 'from_user' looks odd, but we're sending 
					   the message back to the person from whom we received a tweet. */
					$new_user = 1;
				}
				elseif ( $parsed['building'] && $parsed['bonus'] )
				{
					/* We have a destination and a bonus type identified, dunno if they're good */

					$valid_building = preg_match('/^(1|2|3|4)$/', $parsed['building'] );
					$valid_powerup = $this->powerups[ strtolower( $parsed['bonus'] ) ];

					if ( $valid_powerup )
					{
						/* Due to the 'which I don't recognize' message that gets tacked
						   on when a building number is invalid, we can only show quips
						   when the buildling *is* valid. Also, We don't want to put quips
						   *into* the regular message; we want to tack them onto the end.
						   Hence the excessive use of ternary operators! */
						$this->send_tweet_to(
							$tweet['from_user'], 
							( $new_user ? 'Greetings! ' : '' ) .
							sprintf( $valid_powerup, $parsed['building'] .
								( $valid_building ? '' : " (which I don't recognize)" )
							) .
							(
								$valid_building 
									? ' ' . $this->quips[ array_rand( $this->quips ) ]
									: ''
							)
						);
					}
					else
					{
						$this->send_tweet_to(
							$tweet['from_user'], 
							( $new_user ? 'Greetings! ' : '' ) .
							'If "' . $parsed['bonus'] . '" is a thing, it should ' .
							'happen momentarily at building #' . $parsed['building'] .
							( $valid_building ? '.' : ' (if that building exists, anyway).' )
						);
					}
				}
				else
				{
					if ( preg_match('/.*#help.*/', $tweet['text'] ) )
					{
						$this->send_tweet_to(
							$tweet['from_user'],
							"You can drop a #heart, a #speed booster, or #ammo at " .
							"building #1, #2, #3, or #4."
						);
					}
					elseif ( preg_match('/.*#credits?.*/', $tweet['text'] ) )
					{
						$this->send_tweet_to(
							$tweet['from_user'],
							"Team Zen4SugarLemur: @isaiahcdg @drzaal " .
							"@cvillian098 @bo_banducci @steveemmerich @reybomb " .
							"@labelreader Craig & William."
						);
					}
					elseif ( $new_user )
					{
						$this->send_tweet_to(
							$tweet['from_user'],
							"Greetings! Send a #heart, #speed booster, or #ammo " .
							"to a building by its building number (#1-#4)." .
							'Ex: "@heartdropper Drop #heart at building #3"'
						);
					}
					else
					{
						$this->send_tweet_to(
							$tweet['from_user'],
							'We need two tags: something to drop and a building number. ' .
							'Ex: "@heartdropper send #ammo to building #2"'
						);
					}
				}

				/* Finally, insert each tweet into the database */
				$create_time = strtotime( substr( $tweet['created_at'], strpos( $tweet['created_at'], ',' ) + 2 ) );
				$this->_do_sql(
					'INSERT INTO twitter ' .
					'(tweet_id, created, from_user_id, to_user_id, text, parsed_building, parsed_bonus ) ' .
					'VALUES( ?, ?, ?, ?, ?, ?, ? )',
					array(
						$tweet['id_str'],
						$create_time,
						$tweet['from_user_id_str'],
						$tweet['to_user_id_str'],
						$tweet['text'],
						$parsed['building'],
						$parsed['bonus']
					)
				);


			}
		}
	}

	function parse_tweet( $message )
	{
		preg_match_all('/#([a-z0-9_]+)/i', $message, $matches );
		$hashtags = $matches[1];

		$building_no = '';
		$bonus_type = '';
		foreach ( $hashtags as $hashtag )
		{
			/* the first hashtag that (illegally, per Twitter) consists solely of numbers is the building # */
			if ( preg_match('/^\d+$/', $hashtag ) && ! $building_no )
			{
				$building_no = $hashtag;
			}
			/* the first hashtag that doesn't start with a number is the bonus type */
			elseif ( preg_match('/^[a-z]\w+$/i', $hashtag ) && ! $bonus_type )
			{
				$bonus_type = $hashtag;
			}
		}

		return array(
			'building' => $building_no,
			'bonus' => $bonus_type,
		);
	}

	function send_tweet_to( $to_whom, $message )
	{
		$composed_tweet = '@' . $to_whom . ' ' . $message;
		if ( strlen( $composed_tweet ) <= 133 )
			$composed_tweet .= ' #ggj13';
		$this->send_tweet( $composed_tweet );
	}

	function send_tweet( $message )
	{
		$this->twitter->request(
			'POST',
			$this->twitter->url('1/statuses/update'),
			array('status' => $message )
		);
	}

	/* Unfortunately, we throw away every query we construct, yet prepare() is
	the only way to get decent placeholder support in PHP; this little function
	takes the grunt work out of preparing and executing statements and returns
	only the results (if there are any) or success/failure for non-SELECTs */
	function _do_sql( $query, $parameters = NULL )
	{
		$prepared_query = $this->db->prepare( $query );
		if ( is_array( $parameters ) )
		{
			if ( ! $prepared_query->execute( $parameters ) )
				return;
		}
		else
		{
			if ( ! $prepared_query->execute() )
				return;
		}

		/* If the query was expected to return something... */
		if ( preg_match( '/select/i', $query ) )
			/* ...fetch results */
			return $prepared_query->fetchAll();
		else
			/* ...otherwise, we know it didn't fail, so return true */
			return true;
	}
}
